package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.extra.cglib.CglibUtil;
import cn.lili.cache.Cache;
import cn.lili.cache.CachePrefix;
import cn.lili.cache.LockPrefix;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.utils.DateUtil;
import cn.lili.common.utils.ResultUtil;
import cn.lili.common.utils.StringUtils;
import cn.lili.common.vo.ResultMessage;
import cn.lili.modules.goods.client.GoodsClient;
import cn.lili.modules.goods.client.GoodsSkuClient;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsMarketEnum;
import cn.lili.modules.goods.entity.enums.GoodsTypeEnum;
import cn.lili.modules.member.client.UserClient;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.order.order.client.OrderClient;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dos.OrderItem;
import cn.lili.modules.order.order.entity.dos.OrderItemError;
import cn.lili.modules.promotion.entity.dos.*;
import cn.lili.modules.promotion.entity.dto.CallbackBlindboxDTO;
import cn.lili.modules.promotion.entity.dto.search.BoxMhGoodsSearchParams;
import cn.lili.modules.promotion.entity.vos.BoxMhgoodsTagVO;
import cn.lili.modules.promotion.entity.vos.BoxMhgoodsVO;
import cn.lili.modules.promotion.service.*;
import cn.lili.modules.system.client.DictionaryClient;
import cn.lili.modules.system.constants.DictConstant;
import cn.lili.modules.system.entity.dos.Dictionary;
import cn.lili.mybatis.util.PageUtil;
import com.alibaba.fastjson.JSONObject;
import com.api.UserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.lili.modules.promotion.mapper.BoxMhgoodsMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.joda.time.DateTimeConstants;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.json.Json;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author asus
* @description 针对表【box_mhgoods(盲盒商品管理)】的数据库操作Service实现
* @createDate 2023-11-21 10:26:26
*/
@Service
@AllArgsConstructor
@Slf4j
public class BoxMhgoodsServiceImpl extends ServiceImpl<BoxMhgoodsMapper, BoxMhgoods> implements BoxMhgoodsService{

    private DictionaryClient dictionaryClient;
    private GoodsClient goodsClient;
    private GoodsSkuClient goodsSkuClient;
    private BoxOptionService boxOptionService;
    private BoxMhgoodsTagService boxMhgoodsTagService;
    private RedissonClient redisson;
    private BoxLotteryTicketService boxLotteryTicketService;
    private BlindboxRuleOrderService blindboxRuleOrderService;
    private UserClient userClient;
    private UserApi userApi;
    private BoxWinningRecordService boxWinningRecordService;
    private OrderClient orderClient;
    private Cache cache;

    @Override
    public ResultMessage<Object> pageBoxGoods(BoxMhGoodsSearchParams params) {
        log.info("BoxMhGoodsSearchParams params == {}" , JSONObject.toJSONString(params));
        Page<BoxMhgoods> mhgoodsPage = super.page(PageUtil.initPage(params), this.createLambdaQueryWrapper(params));
        return ResultUtil.data(this.conversion(mhgoodsPage));
    }

    /**
     * 批量删除盲盒
     *
     * @param ids id集合
     * @return 是否成功
     */
    @Override
    public ResultMessage<Object> deleteBoxGoods(String ids) {
        log.info("deleteBoxGoods ids === {}", ids);
        LambdaUpdateWrapper<BoxMhgoods> boxMhgoodsLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        boxMhgoodsLambdaUpdateWrapper.set(BoxMhgoods::getDeleteFlag, Boolean.TRUE);
        boxMhgoodsLambdaUpdateWrapper.in(BoxMhgoods::getId, (Object[]) ids.split(","));
        super.update(null, boxMhgoodsLambdaUpdateWrapper);

        //删除规则盲盒的商品
        List<String> removeBoxIdList = new ArrayList<>();
        for (String mhId : ids.split(",")) {
            Goods goods = goodsClient.getGoodsByParams(GoodsSearchParams.builder().mhId(mhId).isMh(true).goodsType(GoodsTypeEnum.BOX_GOODS.name()).build());
            if (goods != null && StringUtils.isNotEmpty(goods.getId())) {
                removeBoxIdList.add(goods.getId());
            }
        }
        log.info("removeBoxIdList === {} ", JSONObject.toJSONString(removeBoxIdList));
        goodsClient.deleteGoods(removeBoxIdList);
        return ResultUtil.success();
    }

    /**
     * 修改盲盒
     *
     * @param boxMhgoodsVO 盲盒对象参数
     * @return 是否成功
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public ResultMessage<Object> updateBoxGoods(BoxMhgoodsVO boxMhgoodsVO) {
        if (StringUtils.isEmpty(boxMhgoodsVO.getId())) {
            throw new ServiceException("盲盒ID为空");
        }
        BoxMhgoods boxMhgoods = super.getById(boxMhgoodsVO.getId());
        Goods goods = goodsClient.getGoodsByParams(GoodsSearchParams.builder().mhId(boxMhgoodsVO.getId()).isMh(true).goodsType(GoodsTypeEnum.BOX_GOODS.name()).build());
        if (goods == null || StringUtils.isEmpty(goods.getId())) {
            log.info("boxMhGoodsVO == {}", JSONObject.toJSONString(boxMhgoodsVO));
            throw new ServiceException("未获取到盲盒信息");
        }
        //已发布后，不允许修改奖券前缀与 大奖商品
        if (DictConstant.PUBLISH_TYPE_01.equals(boxMhgoods.getPublishType()))  {
            if (StringUtils.isNotEmpty(boxMhgoods.getMhPrefix()) && !boxMhgoods.getMhPrefix().equals(boxMhgoodsVO.getMhPrefix())) {
                throw new ServiceException("发布后不允许修改盲盒前缀");
            }
            if (StringUtils.isNotEmpty(boxMhgoods.getBigGoodsId()) && !boxMhgoods.getBigGoodsId().equals(boxMhgoodsVO.getBigGoodsId())) {
                throw new ServiceException("发布后不允许修改大奖商品");
            }
        }
        this.check(boxMhgoodsVO);

        //添加购买方案与标签
        this.addOptionAndTag(boxMhgoodsVO);
        //修改商品数据
        goods.setPrice(boxMhgoodsVO.getMhGoodsPrice().doubleValue());
        goods.setGoodsName(boxMhgoodsVO.getMhGoodsName());
        goods.setThumbnail(boxMhgoodsVO.getMhGoodsHomeImage());
        goods.setBig(boxMhgoodsVO.getMhGoodsHomeImage());
        goods.setSmall(boxMhgoodsVO.getMhGoodsHomeImage());
        goods.setOriginal(boxMhgoodsVO.getMhGoodsHomeImage());
        goods.setIntro(boxMhgoodsVO.getRemark());
        goods.setMobileIntro(boxMhgoodsVO.getRemark());
        cache.remove(CachePrefix.GOODS.getPrefix() + goods.getId());
        goodsClient.updateById(goods);

        //同步修改sku数据
        List<String> goodsId = new ArrayList<>();
        goodsId.add(goods.getId());
        List<GoodsSku> skuList = goodsSkuClient.getGoodsSkuByGoodsIdList(goodsId);
        if (CollectionUtil.isNotEmpty(skuList)) {
            for (GoodsSku goodsSku : skuList) {
                goodsSku.setPrice(goods.getPrice());
                goodsSku.setThumbnail(goods.getThumbnail());
                goodsSku.setBig(goods.getBig());
                goodsSku.setSmall(goods.getSmall());
                goodsSku.setOriginal(goods.getOriginal());
                goodsSku.setIntro(goods.getIntro());
                goodsSku.setMobileIntro(goods.getMobileIntro());

                cache.remove(CachePrefix.GOODS_SKU.getPrefix() + goodsSku.getId());
            }
            goodsSkuClient.updateBatchById(skuList);
        }
        return ResultUtil.data(super.updateById(boxMhgoodsVO));
    }

    /**
     * 添加盲盒
     *
     * @param boxMhgoodsVO 盲盒参数
     * @return 是否成功
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public ResultMessage<Object> addBoxGoods(BoxMhgoodsVO boxMhgoodsVO) {
        boxMhgoodsVO.setId(null);
        boxMhgoodsVO.setPublishType(DictConstant.PUBLISH_TYPE_00);
        boxMhgoodsVO.setMhStatus(DictConstant.MH_STATUS_01);
        this.check(boxMhgoodsVO);
        boolean save = super.save(boxMhgoodsVO);
        //添加购买方案与标签
        this.addOptionAndTag(boxMhgoodsVO);
        //创建与盲盒对应的商品
        boolean isGoods = goodsClient.createGoods(boxMhgoodsVO);
        return ResultUtil.data(save);
    }

    /**
     * 校验参数
     * @param boxMhgoodsVO 参数
     */
    private void check(BoxMhgoodsVO boxMhgoodsVO) {
        log.info("check boxMhgoodsVO == {} ", JSONObject.toJSONString(boxMhgoodsVO));
        if (CollectionUtil.isEmpty(boxMhgoodsVO.getBoxOptionList())) {
            throw new ServiceException("购买方案为空");
        }
        if (CollectionUtil.isEmpty(boxMhgoodsVO.getMhgoodsTagList())) {
            throw new ServiceException("盲盒概率设置为空");
        }
        if (CollectionUtil.isEmpty(boxMhgoodsVO.getDemoMhgoodsTagList())) {
            throw new ServiceException("盲盒试玩概率设置为空");
        }
        if (StringUtils.isEmpty(boxMhgoodsVO.getMhGoodsName())) {
            throw new ServiceException("盲盒名称为空");
        }
        if (StringUtils.isEmpty(boxMhgoodsVO.getMhGoodsHomeImage())) {
            throw new ServiceException("盲盒首页图为空");
        }
        if (StringUtils.isEmpty(boxMhgoodsVO.getMhGoodsBottomImage())) {
            throw new ServiceException("盲盒底部为空");
        }
        if (boxMhgoodsVO.getMhGoodsPrice() == null) {
            throw new ServiceException("盲盒价格为空");
        }
        if (boxMhgoodsVO.getTag() == null) {
            throw new ServiceException("盲盒标签为空");
        }
        if (boxMhgoodsVO.getLotteryMethod() == null) {
            throw new ServiceException("盲盒开奖方式为空");
        }
        if (boxMhgoodsVO.getLotteryConditions() == null) {
            throw new ServiceException("盲盒开奖条件为空");
        }
//        if (StringUtils.isEmpty(boxMhgoodsVO.getPayType())) {
//            throw new ServiceException("盲盒支持的支付方式为空");
//        }
        if (StringUtils.isEmpty(boxMhgoodsVO.getMhPrefix())) {
            throw new ServiceException("盲盒奖券前缀为空");
        }
        if (boxMhgoodsVO.getIsNewUser() == null) {
            throw new ServiceException("是否新用户活动为空");
        }
        if (boxMhgoodsVO.getIsNewUser().equals(DictConstant.YES_NO_01)) {
            if (boxMhgoodsVO.getNewUserPrice() == null) {
                throw new ServiceException("是新人活动，但新人价格为空");
            }
            if (boxMhgoodsVO.getNewUserMinCount() == null) {
                throw new ServiceException("是新人活动，但最少购买数量为空");
            }

            for (BoxOption boxOption : boxMhgoodsVO.getBoxOptionList()) {
                if (boxOption.getOptionType() <= boxMhgoodsVO.getNewUserMinCount()) {
                    throw new ServiceException("购买方案数量 小于等于 新人最少购买数量：" + boxOption.getOptionName());
                }
            }
        }

        if (CollectionUtil.isNotEmpty(boxMhgoodsVO.getMhgoodsTagList())) {
            BigDecimal tagSum = BigDecimal.valueOf(0);
            for (BoxMhgoodsTag mhgoodsTag : boxMhgoodsVO.getMhgoodsTagList()) {
                tagSum = tagSum.add(mhgoodsTag.getProbability());
            }
            if (!(tagSum.doubleValue() == BigDecimal.valueOf(100).doubleValue())) {
                throw new ServiceException("概率总和不等于100，请检查概率设置");
            }
        }
        if (CollectionUtil.isNotEmpty(boxMhgoodsVO.getDemoMhgoodsTagList())) {
            BigDecimal tagSum = BigDecimal.valueOf(0);
            for (BoxMhgoodsTag mhgoodsTag : boxMhgoodsVO.getDemoMhgoodsTagList()) {
                tagSum = tagSum.add(mhgoodsTag.getProbability());
            }
            if (!(tagSum.doubleValue() == BigDecimal.valueOf(100).doubleValue())) {
                throw new ServiceException("试玩概率总和不等于100，请检查概率设置");
            }
        }

        boolean isAddDict = false;
        //判断是否存在该奖券前缀
        LambdaQueryWrapper<BoxMhgoods> queryWrapper = new LambdaQueryWrapper<BoxMhgoods>().eq(BoxMhgoods::getMhPrefix, boxMhgoodsVO.getMhPrefix()).eq(BoxMhgoods::getDeleteFlag, Boolean.FALSE);
        log.info("boxMhgoodsVO.getId() == {}",  boxMhgoodsVO.getId());
        if (StringUtils.isNotEmpty(boxMhgoodsVO.getId())) {
            //修改盲盒前缀,需活动未开始期间修改。
            BoxMhgoods boxMhgoods = super.getById(boxMhgoodsVO);
            boolean notMhPrefix = !boxMhgoodsVO.getMhPrefix().equals(boxMhgoods.getMhPrefix());
            boolean mhStatus = !DictConstant.MH_STATUS_01.equals(boxMhgoods.getMhStatus());
            log.info("notMhPrefix == {},  mhStatus == {} ", notMhPrefix, mhStatus);
            if (mhStatus && notMhPrefix) {
                throw new ServiceException("活动已开始，不允许修改奖券前缀");
            }
            //修改了盲盒前缀同步修改字典前缀。
            if (notMhPrefix) {
                dictionaryClient.updateValueName(boxMhgoods.getMhPrefix(), boxMhgoodsVO.getMhPrefix());
            }
            //编辑的时候删除原数据，从新添加。
            boxOptionService.remove(new LambdaUpdateWrapper<BoxOption>().eq(BoxOption::getMhGoodsId, boxMhgoodsVO.getId()));
            boxMhgoodsTagService.remove(new LambdaUpdateWrapper<BoxMhgoodsTag>().eq(BoxMhgoodsTag::getMhgoodsId, boxMhgoodsVO.getId()));

            queryWrapper.ne(BoxMhgoods::getId, boxMhgoodsVO.getId());
        } else {
            isAddDict = true;
        }
        //判断是否存在该奖券前缀
        long count = super.count(queryWrapper);
        if (count > 0) {
            throw new ServiceException("盲盒奖券前缀已存在："+boxMhgoodsVO.getMhPrefix());
        }
        if (isAddDict) {
            //初始化盲盒前缀数据
            dictionaryClient.save(Dictionary.builder().code(DictConstant.MH_PREFIX_NO).value("0").valueName(boxMhgoodsVO.getMhPrefix()).build());
        }
    }

    public void addOptionAndTag(BoxMhgoodsVO boxMhgoodsVO) {
        //添加购买方案与商品标签中奖概率
        for (BoxOption boxOption : boxMhgoodsVO.getBoxOptionList()) {
            if (boxOption == null) {
                continue;
            }
            boxOption.setMhGoodsId(boxMhgoodsVO.getId());
            boxOptionService.addBoxGoods(boxOption);
        }
        for (BoxMhgoodsTag boxMhgoodsTag : boxMhgoodsVO.getMhgoodsTagList()) {
            if (boxMhgoodsTag == null) {
                continue;
            }
            boxMhgoodsTag.setType(DictConstant.TAG_TYPE_01);
            boxMhgoodsTag.setMhgoodsId(boxMhgoodsVO.getId());
            boxMhgoodsTagService.addBoxGoods(BeanUtil.toBean(boxMhgoodsTag, BoxMhgoodsTagVO.class));
        }
        for (BoxMhgoodsTag boxMhgoodsTag : boxMhgoodsVO.getDemoMhgoodsTagList()) {
            if (boxMhgoodsTag == null) {
                continue;
            }
            boxMhgoodsTag.setType(DictConstant.TAG_TYPE_02);
            boxMhgoodsTag.setMhgoodsId(boxMhgoodsVO.getId());
            boxMhgoodsTagService.addBoxGoods(BeanUtil.toBean(boxMhgoodsTag, BoxMhgoodsTagVO.class));
        }
    }

    @Override
    public ResultMessage<Object> select(String goodsName) {
        LambdaQueryWrapper<BoxMhgoods> lambdaQueryWrapper = this.createLambdaQueryWrapper(BoxMhGoodsSearchParams.builder().goodsName(goodsName).build());
        return ResultUtil.data(super.list(lambdaQueryWrapper.select(BoxMhgoods::getId, BoxMhgoods::getMhGoodsName)));
    }

    private LambdaQueryWrapper<BoxMhgoods> createLambdaQueryWrapper(BoxMhGoodsSearchParams params) {
        LambdaQueryWrapper<BoxMhgoods> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(params.getId())) {
            lambdaQueryWrapper.eq(BoxMhgoods::getId, params.getId());
        }
        if (StringUtils.isNotEmpty(params.getTag())) {
            lambdaQueryWrapper.eq(BoxMhgoods::getTag, params.getTag());
        }
        if (StringUtils.isNotEmpty(params.getGoodsName())) {
            lambdaQueryWrapper.like(BoxMhgoods::getMhGoodsName, params.getGoodsName());
        }
        if (params.getMhStatus() != null) {
            lambdaQueryWrapper.eq(BoxMhgoods::getMhStatus, params.getMhStatus());
        }
        if (params.getPublishType() != null) {
            lambdaQueryWrapper.eq(BoxMhgoods::getPublishType, params.getPublishType());
        }
        if (params.getStartCreateTime() != null) {
            lambdaQueryWrapper.ge(BoxMhgoods::getCreateTime, params.getStartCreateTime());
        }
        if (params.getEndCreateTime() != null) {
            lambdaQueryWrapper.le(BoxMhgoods::getCreateTime, params.getEndCreateTime());
        }
        lambdaQueryWrapper.eq(BoxMhgoods::getDeleteFlag, Boolean.FALSE);
        lambdaQueryWrapper.orderByDesc(BoxMhgoods::getCreateTime);
        return lambdaQueryWrapper;
    }

    /**
     * 查询详情
     *
     * @param id 详情id
     * @return 详情
     */
    @Override
    public ResultMessage<Object> detail(String id) {
        BoxMhgoods boxMhgoods = super.getById(id);
        if (boxMhgoods == null) {
            return ResultUtil.success();
        }
        BoxMhgoodsVO boxMhgoodsVO = new BoxMhgoodsVO();
        BeanUtils.copyProperties(boxMhgoods, boxMhgoodsVO);

        //数据转换
        List<Dictionary> tagList = dictionaryClient.getListByCode(DictConstant.TAG_NAME);
        List<Dictionary> tagTypeList = dictionaryClient.getListByCode(DictConstant.TAG_TYPE_NAME);
        List<Dictionary> mhStatusList = dictionaryClient.getListByCode(DictConstant.MH_STATUS_NO);
        List<Dictionary> lotteryMethodList = dictionaryClient.getListByCode(DictConstant.LOTTERY_METHOD_NO);
        List<Dictionary> yesNoList = dictionaryClient.getListByCode(DictConstant.YES_NO);
        List<Dictionary> optionList = dictionaryClient.getListByCode(DictConstant.OPTION_NO);
        List<Dictionary> publishTypeList = dictionaryClient.getListByCode(DictConstant.PUBLISH_TYPE_NO);
        List<Goods> goodsList = goodsClient.queryListByParams(GoodsSearchParams.builder().id(boxMhgoods.getBigGoodsId()).build());
        this.conversionDetail(boxMhgoodsVO, tagList, mhStatusList, lotteryMethodList, yesNoList, goodsList, publishTypeList);

        List<BoxOption> boxOptionList = boxOptionService.list(new LambdaQueryWrapper<BoxOption>().eq(BoxOption::getMhGoodsId, boxMhgoodsVO.getId()));
        if (CollectionUtil.isNotEmpty(boxOptionList)) {
            List<Goods> biZhongGoodsList = goodsClient.queryListByParams(GoodsSearchParams.builder().id(boxOptionList.stream().map(BoxOption::getBiZhongGoodsId).collect(Collectors.joining(","))).build());
            for (BoxOption boxOption : boxOptionList) {
                if (CollectionUtil.isNotEmpty(biZhongGoodsList)) {
                    List<Goods> biZhongGoods = new ArrayList<>();
                    for (Goods goods : biZhongGoodsList) {
                        if (StringUtils.isNotEmpty(boxOption.getBiZhongGoodsId())) {
                            for (String goodsId : boxOption.getBiZhongGoodsId().split(",")) {
                                if (goodsId.equals(goods.getId())) {
                                    biZhongGoods.add(goods);
                                }
                            }
                        }
                    }
                    boxOption.setGoodsList(biZhongGoods);
                }
                if (CollectionUtil.isNotEmpty(optionList)) {
                    for (Dictionary dictionary : optionList) {
                        if (String.valueOf(boxOption.getOptionType()).equals(dictionary.getValue())) {
                            boxOption.setOptionName(dictionary.getValueName());
                        }
                    }
                }
            }
            boxMhgoodsVO.setBoxOptionList(boxOptionList);
        }
        List<BoxMhgoodsTag> mhgoodsTagList = boxMhgoodsTagService.list(new LambdaQueryWrapper<BoxMhgoodsTag>().eq(BoxMhgoodsTag::getMhgoodsId, boxMhgoodsVO.getId()));
        if (CollectionUtil.isNotEmpty(mhgoodsTagList)) {
            for (BoxMhgoodsTag mhgoodsTag : mhgoodsTagList) {
                if (CollectionUtil.isNotEmpty(tagTypeList)) {
                    for (Dictionary dictionary : tagTypeList) {
                        if (dictionary.getValue().equals(String.valueOf(mhgoodsTag.getType()))) {
                            mhgoodsTag.setTypeName(dictionary.getValueName());
                        }
                    }
                }
                if (CollectionUtil.isNotEmpty(tagList)) {
                    for (Dictionary dictionary : tagList) {
                        if (dictionary.getValue().equals(String.valueOf(mhgoodsTag.getTag()))) {
                            mhgoodsTag.setTagName(dictionary.getValueName());
                        }
                    }
                }
            }
            boxMhgoodsVO.setMhgoodsTagList(mhgoodsTagList.stream().filter(f -> DictConstant.TAG_TYPE_01.equals(f.getType())).collect(Collectors.toList()));
            boxMhgoodsVO.setDemoMhgoodsTagList(mhgoodsTagList.stream().filter(f -> DictConstant.TAG_TYPE_02.equals(f.getType())).collect(Collectors.toList()));
        }
        return ResultUtil.data(boxMhgoodsVO);
    }

    /**
     * 盲盒开关
     *
     * @param id 主键
     * @param publishType 1开，2关
     * @return 是否成功
     */
    @Override
    public ResultMessage<Object> change(String id, Integer publishType) {
        BoxMhgoods boxMhgoods = super.getById(id);
        if (boxMhgoods == null) {
            log.error("未获取到盲盒信息id == {}", id);
            throw new ServiceException("未获取到盲盒信息");
        }
        Goods goods = goodsClient.getGoodsByParams(GoodsSearchParams.builder().mhId(id).isMh(true).goodsType(GoodsTypeEnum.BOX_GOODS.name()).build());
        if (goods == null || StringUtils.isEmpty(goods.getId())) {
            log.error("未获取到商品信息mhId == {}", id);
            throw new ServiceException("未获取到商品信息");
        }
        boxMhgoods.setPublishType(publishType);
        String authFlag = "";
        String marketEnable = "";
        //如果发布了，即代表活动进行中了
        if (DictConstant.PUBLISH_TYPE_01.equals(publishType)) {
            //校验能否发布
            this.changeCheck(boxMhgoods);
            boxMhgoods.setMhStatus(DictConstant.MH_STATUS_02);
            authFlag = GoodsAuthEnum.PASS.name();
            marketEnable = GoodsMarketEnum.UPPER.name();
        } else {
            authFlag = GoodsAuthEnum.TOBEAUDITED.name();
            marketEnable = GoodsMarketEnum.DOWN.name();
        }

        List<String> goodsIdList = new ArrayList<>();
        goodsIdList.add(goods.getId());
        List<GoodsSku> skuList = goodsSkuClient.getGoodsSkuByGoodsIdList(goodsIdList);
        if (CollectionUtil.isNotEmpty(skuList)) {
            for (GoodsSku sku : skuList) {
                sku.setAuthFlag(authFlag);
                sku.setMarketEnable(marketEnable);
                cache.remove(CachePrefix.GOODS_SKU.getPrefix() + sku.getId());
            }
            goodsSkuClient.updateBatchById(skuList);
        }
        super.updateById(boxMhgoods);
        goods.setPublishType(publishType);
        goods.setAuthFlag(authFlag);
        goods.setMarketEnable(marketEnable);

        cache.remove(CachePrefix.GOODS.getPrefix() + goods.getId());
        goodsClient.updateById(goods);
        return ResultUtil.success();
    }

    /**
     * 校验是否能发布
     * 1.判断每个概率标签不为空的，是否有与之对应的商品。   例如 ： 盲盒高级概率 不等于null 和 空  ==》 店铺商品必须存在高级商品
     * 2.概率不为空，但库存小于等于0
     * 3.概率不为空，但所有库存加起来，达不到开奖条件
     */
    public void changeCheck(BoxMhgoods boxMhgoods) {
        //获取盲盒概率
        List<BoxMhgoodsTag> mhgoodsTagList = boxMhgoodsTagService.list(new LambdaQueryWrapper<BoxMhgoodsTag>()
                .eq(BoxMhgoodsTag::getMhgoodsId, boxMhgoods.getId()).eq(BoxMhgoodsTag::getDeleteFlag, Boolean.FALSE));
        //获取盲盒商品
        List<Goods> goodsList = goodsClient.queryListByParams(GoodsSearchParams.builder().mhId(boxMhgoods.getId()).publishType(DictConstant.PUBLISH_TYPE_01).goodsType(GoodsTypeEnum.BOX_PARENT_GOODS.name()).build());
//        Integer totalStock = 0;
        for (BoxMhgoodsTag mhgoodsTag : mhgoodsTagList) {
            //概率不为空
            if (mhgoodsTag.getProbability() != null && mhgoodsTag.getProbability().doubleValue() > 0D) {
                boolean isGoods = true;
                //当前概率下是否存在商品
                for (Goods goods : goodsList) {
                    if (goods.getGoodsTag().equals(mhgoodsTag.getTag())) {
                        isGoods = false;
                        break;
                    }
                }
                //不存在商品不允许发布
                if (isGoods) {
                    Dictionary dict = dictionaryClient.getDict(Dictionary.builder().code(DictConstant.TAG_NAME).value(String.valueOf(mhgoodsTag.getTag())).build());
                    String message = dict != null ? dict.getValueName() + "概率不为空" : "概率不为空";
                    throw new ServiceException(message + "但对应的概率，无商品。请发布商品");
                }

                //2.概率不为空，但库存小于等于0
//                if (mhgoodsTag.getStock() != null && mhgoodsTag.getStock() <= 0) {
//                    throw new ServiceException("概率不为空，但库存小于等于0");
//                }
//                totalStock += mhgoodsTag.getStock() != null ?  mhgoodsTag.getStock() : 0;
            }
        }
//        if (totalStock < boxMhgoods.getLotteryConditions()) {
//            throw new ServiceException("所有库存累加 小于 开奖条件");
//        }
        if (StringUtils.isEmpty(boxMhgoods.getBigGoodsId())) {
            throw new ServiceException("大奖信息不能为空");
        }
    }
    /**
     * 更新奖券状态 ==>  中大奖信息   ==>  通知用户中奖
     *
     * @param id 盲盒ID
     * @return 是否成功
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public ResultMessage<Object> drawNow(String id) {
        log.info("drawNow == {}", id);
        List<BoxLotteryTicket> ticketList = boxLotteryTicketService.list(
                new LambdaQueryWrapper<BoxLotteryTicket>().eq(BoxLotteryTicket::getMhId, id)
                        .eq(BoxLotteryTicket::getLotteryTicketStatus, DictConstant.LOTTERY_TICKET_STATUS_01)
                        .eq(BoxLotteryTicket::getActiveState, DictConstant.ACTIVE_STATE_01)
        );
        if (CollectionUtil.isEmpty(ticketList)) {
            throw new ServiceException("没有待开奖奖券，无法开奖");
        }
        BoxMhgoods boxMhgoods = super.getById(id);
        if (boxMhgoods == null) {
            throw new ServiceException("未获取到，盲盒商品信息");
        }
        if (DictConstant.MH_STATUS_04.equals(boxMhgoods.getMhStatus())) {
            throw new ServiceException("盲盒已开奖，不能重复开奖");
        }
        Goods goods = goodsClient.getById(boxMhgoods.getBigGoodsId());
        if (goods == null || StringUtils.isEmpty(goods.getId())) {
            throw new ServiceException("未获取到大奖信息");
        }
        //更新奖券状态
        LambdaUpdateWrapper<BoxLotteryTicket> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BoxLotteryTicket::getMhId, id);
        updateWrapper.set(BoxLotteryTicket::getActiveState, DictConstant.ACTIVE_STATE_02);
        boxLotteryTicketService.update(updateWrapper);

        BoxLotteryTicket boxLotteryTicket = ticketList.get(new SecureRandom().nextInt(ticketList.size()));
        updateWrapper.clear();
        updateWrapper.eq(BoxLotteryTicket::getId, boxLotteryTicket.getId());
        updateWrapper.set(BoxLotteryTicket::getLotteryTicketStatus, DictConstant.LOTTERY_TICKET_STATUS_02);
        boxLotteryTicketService.update(updateWrapper);

        User user = userClient.getById(boxLotteryTicket.getUserId());
        if (user == null || StringUtils.isEmpty(user.getId())) {
            throw new ServiceException("未获取到中奖用户信息");
        }
        //更新盲盒状态
        boxMhgoods.setMhStatus(DictConstant.MH_STATUS_04);
        super.updateById(boxMhgoods);
        //TODO 大奖与中奖用户，进行绑定
        this.goodsBindUser(goods, boxMhgoods, boxLotteryTicket, user);

        //TODO 中奖信息，通知飞语用户
//        String content = "商品：" + boxMhgoods.getMhGoodsName() + "," + "中奖人飞语昵称：" + user.getFyName() + ", 中奖人飞语号：" + user.getUsername();
//        userApi.sendMessage("大奖信息公布", content,null);

        return ResultUtil.success();
    }


    /**
     * 大奖与中奖用户，进行绑定
     */
    private void goodsBindUser(Goods goods, BoxMhgoods boxMhgoods, BoxLotteryTicket boxLotteryTicket, User user) {
        BoxWinningRecord boxWinningRecord = new BoxWinningRecord();
        boxWinningRecord.setGoodsId(goods.getId());
        boxWinningRecord.setGoodsName(goods.getGoodsName());
        boxWinningRecord.setGoodsImage(StringUtils.isNotEmpty(goods.getThumbnail()) ? goods.getThumbnail() : goods.getBig());
        boxWinningRecord.setUsername(user.getUsername());
        boxWinningRecord.setUserId(user.getId());
        boxWinningRecord.setMhName(boxMhgoods.getMhGoodsName());
        boxWinningRecord.setMhId(boxMhgoods.getId());
        boxWinningRecord.setWinningRecordStatus(DictConstant.WINNING_RECORD_STATUS_01);
        boxWinningRecord.setLotteryTicketNo(boxLotteryTicket.getLotteryTicketNo());
        boxWinningRecord.setLotteryTicketId(boxLotteryTicket.getId());
        boxWinningRecord.setLotteryMethod(boxMhgoods.getLotteryMethod());
        boxWinningRecord.setOrderTime(boxLotteryTicket.getCreateTime());
        boxWinningRecord.setDrawingTime(new Date());
        boxWinningRecord.setShareOrNot(DictConstant.YES_NO_00);

        boxWinningRecordService.save(boxWinningRecord);
    }

    /**
     * 下单后生成奖券 + 创建奖品订单 与订单进行关联  + 判断是否达到开奖条件（到达变更状态，待开奖。App则不能进行购买了）
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public List<Goods> callbackMhGoods(CallbackBlindboxDTO callbackBlindboxDTO) {
        log.info("1.进入盲盒V2流程  === {}" ,JSONObject.toJSONString(callbackBlindboxDTO));
        //获取盲盒数据
        Goods goods = goodsClient.getGoodsByParams(GoodsSearchParams.builder().id(callbackBlindboxDTO.getGoodsId()).isMh(true).publishType(DictConstant.PUBLISH_TYPE_01).goodsType(GoodsTypeEnum.BOX_GOODS.name()).build());
        if (goods == null || StringUtils.isEmpty(goods.getId()) || StringUtils.isEmpty(goods.getMhId())) {
            log.error("未获取到商品信息 == {}" , callbackBlindboxDTO.getGoodsId());
            throw new ServiceException("未获取到商品信息");
        }
        BoxMhgoods boxMhgoods = super.getById(goods.getMhId());
        if (boxMhgoods == null) {
            log.error("未获取到盲盒数据 == {}", JSONObject.toJSONString(callbackBlindboxDTO));
            throw new ServiceException("未获取到盲盒数据");
        }
        //创建订单与盲盒奖品的关系
        List<Goods> orderMhGoods = this.createOrderMhGoods(callbackBlindboxDTO, boxMhgoods);
        //如果奖券到达开奖条件。设置成待开奖。App端不能再购买了。并设置开奖时间
        long boxLotteryTicketCount = boxLotteryTicketService.count(new LambdaQueryWrapper<BoxLotteryTicket>()
                .eq(BoxLotteryTicket::getMhId, boxMhgoods.getId())
                .in(BoxLotteryTicket::getLotteryTicketStatus, DictConstant.LOTTERY_TICKET_STATUS_01, DictConstant.LOTTERY_TICKET_STATUS_02));
        if (boxLotteryTicketCount >= boxMhgoods.getLotteryConditions()) {
            boxMhgoods.setMhStatus(DictConstant.MH_STATUS_03);
            //设置开奖时间 ：  当前时间  + 原有设置的 时分  =  开奖时间
            LocalDate currentDate = LocalDate.now();
            Date date = boxMhgoods.getLotteryTime() != null ? boxMhgoods.getLotteryTime() : new Date();
            LocalTime localTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
            LocalTime customTime = LocalTime.of(localTime.getHour(), localTime.getMinute());
            LocalDateTime dateTime = LocalDateTime.of(currentDate, customTime);
            boxMhgoods.setLotteryDate(Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()));
        }
        super.updateById(boxMhgoods);
        log.info("2.盲盒V2流程执行完毕");
        return orderMhGoods;
    }

    /**
     * 生成奖券
     */
    private void createLotteryTicket(CallbackBlindboxDTO callbackBlindboxDTO, BoxMhgoods boxMhgoods, Goods goods) {
        BoxLotteryTicket ticket = new BoxLotteryTicket();
        ticket.setMhId(boxMhgoods.getId());
        ticket.setMhName(boxMhgoods.getMhGoodsName());
        ticket.setMhTag(goods.getGoodsTag());
        ticket.setGoodsId(goods.getId());
        ticket.setLotteryTicketStatus(DictConstant.LOTTERY_TICKET_STATUS_01);
        ticket.setUserId(callbackBlindboxDTO.getUserId());
        User user = userClient.getById(callbackBlindboxDTO.getUserId());
        ticket.setUserName(user != null && StringUtils.isNotEmpty(user.getUsername()) ? user.getUsername() : null);
        ticket.setActiveState(DictConstant.ACTIVE_STATE_01);
        ticket.setLotteryTicketNo(this.getLotteryTicketNo(boxMhgoods.getMhPrefix()));
        ticket.setOrderId(callbackBlindboxDTO.getOrderId());
        ticket.setOrderSn(callbackBlindboxDTO.getOrderSn());
        boxLotteryTicketService.save(ticket);
    }

    /**
     * 获取奖券号码
     *
     * @param mhPrefix 号码前缀
     * @return 奖券号码
     */
    private String getLotteryTicketNo(String mhPrefix) {
        String lotteryNo = dictionaryClient.autoIncrement(mhPrefix, DictConstant.MH_PREFIX_NO);
        if (StringUtils.isEmpty(lotteryNo)) {
            log.error("getLotteryTicketNo === {} ", mhPrefix);
            throw new ServiceException("未获取到字典前缀值");
        }
        long count = boxLotteryTicketService.count(new LambdaQueryWrapper<BoxLotteryTicket>().eq(BoxLotteryTicket::getLotteryTicketNo, lotteryNo));
        if (count > 0) {
            //号码重复，重新生成
            this.getLotteryTicketNo(mhPrefix);
        }
        return lotteryNo;
    }

    /**
     * 创建奖品与订单的关系  并生成奖券号码
     */
    private List<Goods> createOrderMhGoods(CallbackBlindboxDTO callbackBlindboxDTO, BoxMhgoods boxMhgoods) {
        //根据规则查询奖品
        List<BoxMhgoodsTag> mhgoodsTagList = boxMhgoodsTagService.list(new LambdaQueryWrapper<BoxMhgoodsTag>()
                .eq(BoxMhgoodsTag::getType, DictConstant.TAG_TYPE_01)
                .eq(BoxMhgoodsTag::getMhgoodsId, boxMhgoods.getId()));
        //当诗史和传说，无库存时。不查询出来。
        StringBuilder tagList = new StringBuilder(DictConstant.TAG_01 + StringPool.COMMA + DictConstant.TAG_02);
        for (BoxMhgoodsTag mhgoodsTag : mhgoodsTagList) {
            if (DictConstant.TAG_03.equals(mhgoodsTag.getTag()) && mhgoodsTag.getStock() > 0) {
                tagList.append(StringPool.COMMA + DictConstant.TAG_03);
            }
            if (DictConstant.TAG_04.equals(mhgoodsTag.getTag()) && mhgoodsTag.getStock() > 0) {
                tagList.append(StringPool.COMMA + DictConstant.TAG_04);
            }
        }
        List<Goods> goodsList = goodsClient.queryListByParams(GoodsSearchParams.builder().goodsTagList(tagList.toString()).mhId(boxMhgoods.getId()).publishType(DictConstant.PUBLISH_TYPE_01).goodsType(GoodsTypeEnum.BOX_PARENT_GOODS.name()).build());
        List<Goods> resultGoods = new ArrayList<>();
        //新增奖品订单
        for (int i = 0; i < callbackBlindboxDTO.getOrderNumber(); i++) {
            Goods goods = this.pickOne(goodsList, boxMhgoods.getId(), true);
            log.info("pickOne == {}", JSONObject.toJSONString(goods));
            //第一进来，去判断有没有必中策略。如果有则选择必中商品
            if (i == 0) {
                Goods createGoods = this.create(callbackBlindboxDTO, boxMhgoods, goods);
                resultGoods.add(createGoods);
                continue;
            }
            Goods createGoods = this.createGoods(callbackBlindboxDTO, boxMhgoods, goods);
            //更新tag库存数量
            this.subtractStock(boxMhgoods.getId(), createGoods.getGoodsTag());
            resultGoods.add(createGoods);
        }
        //盲盒信息反添到订单上
        Order order = new Order();
        order.setSn(callbackBlindboxDTO.getOrderSn());
        order.setMhId(boxMhgoods.getId());
        order.setMhName(boxMhgoods.getMhGoodsName());
        orderClient.update(order);
        return resultGoods;
    }

    /**
     * 库存减1
     * @param id 盲盒ID
     * @param goodsTag 商品类型
     */
    public void subtractStock(String id, Integer goodsTag) {
        BoxMhgoodsTag mhgoodsTag = boxMhgoodsTagService.getOne(new LambdaQueryWrapper<BoxMhgoodsTag>()
                .eq(BoxMhgoodsTag::getMhgoodsId, id)
                .eq(BoxMhgoodsTag::getTag, goodsTag)
                .eq(BoxMhgoodsTag::getType, DictConstant.TAG_TYPE_01).last("limit 1"));
        mhgoodsTag.setStock(mhgoodsTag.getStock() != null ? mhgoodsTag.getStock() -1 : 0);
        boxMhgoodsTagService.updateById(mhgoodsTag);
    }

    /**
     * 创建奖品与订单的关系  并生成奖券号码
     */
    private Goods createGoods(CallbackBlindboxDTO callbackBlindboxDTO, BoxMhgoods boxMhgoods, Goods goods) {
        if (goods != null) {
            log.info("生成奖券并创建订单与奖品的关系, createGoods ：  callbackBlindboxDTO == {},  boxMhgoods == {},  goods == {}",
                    JSONObject.toJSONString(callbackBlindboxDTO),  JSONObject.toJSONString(boxMhgoods), JSONObject.toJSONString(goods));
            //生成奖券号码
            this.createLotteryTicket(callbackBlindboxDTO, boxMhgoods, goods);
            //创建奖品与订单的关系
            BlindboxRuleOrder blindboxRuleOrder = new BlindboxRuleOrder();
            blindboxRuleOrder.setRuleId(boxMhgoods.getId());
            blindboxRuleOrder.setRuleGoodsId(goods.getId());
            blindboxRuleOrder.setRuleGoodsName(goods.getGoodsName());
            blindboxRuleOrder.setRuleGoodsImage(goods.getThumbnail());
            blindboxRuleOrder.setOrderSn(callbackBlindboxDTO.getOrderSn());
            blindboxRuleOrder.setOrderItemSn(callbackBlindboxDTO.getOrderItemSn());
            blindboxRuleOrderService.save(blindboxRuleOrder);
        }
        return goods;
    }

    /**
     * 有必中策略：选择必中商品。否则正常流程：随机商品
     */
    private Goods create(CallbackBlindboxDTO callbackBlindboxDTO, BoxMhgoods boxMhgoods, Goods goods) {
        List<BoxOption> tagList = boxOptionService.list(new LambdaQueryWrapper<BoxOption>().eq(BoxOption::getMhGoodsId, boxMhgoods.getId()));
        BoxOption option = null;
        for (BoxOption boxOption : tagList) {
            //购买几次，代表几连抽。然后匹配连抽必中策略
            if (callbackBlindboxDTO.getOrderNumber().equals(boxOption.getOptionType())) {
                option = boxOption;
                log.info("找到了购买方案, 方案 === {},callbackBlindboxDTO == {} ", JSONObject.toJSONString(option), JSONObject.toJSONString(callbackBlindboxDTO));
                break;
            }
        }
        if (option != null && StringUtils.isNotEmpty(option.getBiZhongGoodsId())) {
            //随机一个必中商品
            List<String> goodsIdList = Arrays.stream(option.getBiZhongGoodsId().split(",")).toList();
            Goods optionGoods = goodsClient.getById(goodsIdList.get(new SecureRandom().nextInt(goodsIdList.size())));
            if (optionGoods == null || StringUtils.isEmpty(optionGoods.getId())) {
                log.error("命中必中策略，但必中商品为空option === {}, callbackBlindboxDTO == {}", JSONObject.toJSONString(option) , JSONObject.toJSONString(callbackBlindboxDTO));
                this.subtractStock(boxMhgoods.getId(), goods.getGoodsTag());
                return this.createGoods(callbackBlindboxDTO, boxMhgoods, goods);
            }
            log.info("获得必中商品 == {}", JSONObject.toJSONString(optionGoods));
            return this.createGoods(callbackBlindboxDTO, boxMhgoods, optionGoods);
        }
        this.subtractStock(boxMhgoods.getId(), goods.getGoodsTag());
        return this.createGoods(callbackBlindboxDTO, boxMhgoods, goods);
    }

    /**
     * 随机奖品
     * 根据概率获取标签  ==>  在根据标签获取，所属标签的商品
     * @return 中奖商品
     */
    public Goods pickOne(List<Goods> goodsList, String id, Boolean type) {
        LambdaQueryWrapper<BoxMhgoodsTag> wrapper = new LambdaQueryWrapper<BoxMhgoodsTag>().eq(BoxMhgoodsTag::getMhgoodsId, id);
        if (type != null) {
            //true是购买时的概率。false是试玩概率
            if (type) {
                wrapper.eq(BoxMhgoodsTag::getType, DictConstant.TAG_TYPE_01);
            } else {
                wrapper.eq(BoxMhgoodsTag::getType, DictConstant.TAG_TYPE_02);
            }
        }
        List<BoxMhgoodsTag> mhgoodsTagList = boxMhgoodsTagService.list(wrapper);
        BoxMhgoodsTag tag = this.getLotteryItem(mhgoodsTagList);
        if (tag == null) {
            log.error("未获取到标签数据 == {}", JSONObject.toJSONString(mhgoodsTagList));
            throw new ServiceException("未获取到标签数据");
        }
        List<Goods> list = goodsList.stream().filter(f -> tag.getTag().equals(f.getGoodsTag())).toList();
        //如果对应标签下，没有商品则重新选择标签
        if (CollectionUtil.isEmpty(list) || ((DictConstant.TAG_03.equals(tag.getTag()) || DictConstant.TAG_04.equals(tag.getTag())) && tag.getStock() != null && tag.getStock() <= 0)) {
            log.info("tag === {},goodsList == {}", tag, JSONObject.toJSONString(goodsList));
            return this.pickOne(goodsList, id, type);
        }
        return list.get(new SecureRandom().nextInt(list.size()));
    }

    /**
     * 从一个奖品列表中随机选取一个奖品，选取时会根据每个奖品的概率进行加权随机，并返回选中的奖品。
     *
     * 首先，遍历奖品列表，计算所有奖品的概率之和。
     * 生成一个随机值，其取值范围为 [0, probabilitySum]，其中 probabilitySum 为所有奖品的概率之和。
     * 遍历奖品列表，累加每个奖品的概率，直到当前概率之和大于随机值为止。此时，即可确定选中的奖品。
     *
     * 根据概率获取一个标签
     */
    public BoxMhgoodsTag getLotteryItem(List<BoxMhgoodsTag> mhgoodsTagList) {
        BigDecimal probabilitySum = BigDecimal.valueOf(0);
        for (BoxMhgoodsTag item : mhgoodsTagList) {
            probabilitySum = probabilitySum.add(item.getProbability());
        }
        BigDecimal randomValue = BigDecimal.valueOf(new SecureRandom().nextDouble()).multiply(probabilitySum);
        BigDecimal currentProbability = BigDecimal.valueOf(0);
        for (BoxMhgoodsTag mhgoodsTag : mhgoodsTagList) {
            currentProbability = currentProbability.add(mhgoodsTag.getProbability());
            if (randomValue.compareTo(currentProbability) < 0) {
                return mhgoodsTag;
            }
        }
        //如果随机值大于所有奖品的概率之和，返回null
        log.error("随机值大于所有奖品的概率之和，请检查配置 == {} ", JSONObject.toJSONString(mhgoodsTagList));
        throw new ServiceException("随机值大于所有奖品的概率之和，请检查配置");
    }

    private Page<BoxMhgoodsVO> conversion(Page<BoxMhgoods> paramsPage) {
        //复制page对象
        if (CollectionUtil.isEmpty(paramsPage.getRecords())) {
            return new Page<BoxMhgoodsVO>();
        }
        Page<BoxMhgoodsVO> resultPage = new Page<>();
        BeanUtils.copyProperties(paramsPage, resultPage);
        List<BoxMhgoodsVO> voList = CglibUtil.copyList(paramsPage.getRecords(), BoxMhgoodsVO::new);
        resultPage.setRecords(voList);

        //字典转换
        List<Dictionary> tagList = dictionaryClient.getListByCode(DictConstant.TAG_NAME);
        List<Dictionary> mhStatusList = dictionaryClient.getListByCode(DictConstant.MH_STATUS_NO);
        List<Dictionary> lotteryMethodList = dictionaryClient.getListByCode(DictConstant.LOTTERY_METHOD_NO);
        List<Dictionary> yesNoList = dictionaryClient.getListByCode(DictConstant.YES_NO);
        List<Dictionary> publishTypeList = dictionaryClient.getListByCode(DictConstant.PUBLISH_TYPE_NO);
        List<Goods> goodsList = goodsClient.queryListByParams(GoodsSearchParams.builder().id(resultPage.getRecords().stream().map(BoxMhgoodsVO::getBigGoodsId).collect(Collectors.joining(","))).build());
        for (BoxMhgoodsVO boxMhgoodsVO : resultPage.getRecords()) {
            this.conversionDetail(boxMhgoodsVO, tagList, mhStatusList, lotteryMethodList, yesNoList, goodsList, publishTypeList);
        }
        return resultPage;
    }

    public void conversionDetail(BoxMhgoodsVO boxMhgoodsVO, List<Dictionary> tagList, List<Dictionary> mhStatusList, List<Dictionary> lotteryMethodList, List<Dictionary> yesNoList, List<Goods> goodsList, List<Dictionary> publishTypeList) {
        if (CollectionUtil.isNotEmpty(tagList)) {
            for (Dictionary dictionary : tagList) {
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getTag()))) {
                    boxMhgoodsVO.setTagName(dictionary.getValueName());
                    break;
                }
            }
        }
        if (CollectionUtil.isNotEmpty(mhStatusList)) {
            for (Dictionary dictionary : mhStatusList) {
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getMhStatus()))) {
                    boxMhgoodsVO.setMhStatusName(dictionary.getValueName());
                    break;
                }
            }
        }
        if (CollectionUtil.isNotEmpty(lotteryMethodList)) {
            for (Dictionary dictionary : lotteryMethodList) {
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getLotteryMethod()))) {
                    boxMhgoodsVO.setLotteryMethodName(dictionary.getValueName());
                    break;
                }
            }
        }
        if (CollectionUtil.isNotEmpty(yesNoList)) {
            for (Dictionary dictionary : yesNoList) {
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getIsNewUser()))) {
                    boxMhgoodsVO.setIsNewUserName(dictionary.getValueName());
                }
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getIsParameterActivity()))) {
                    boxMhgoodsVO.setIsParameterActivityName(dictionary.getValueName());
                }
            }
        }
        if (CollectionUtil.isNotEmpty(goodsList)) {
            for (Goods goods : goodsList) {
                if (goods.getId().equals(boxMhgoodsVO.getBigGoodsId())) {
                    boxMhgoodsVO.setBigGoodsName(goods.getGoodsName());
                    boxMhgoodsVO.setBigGoodsImage(StringUtils.isNotEmpty(goods.getThumbnail()) ? goods.getThumbnail() : goods.getBig());
                    break;
                }
            }
        }
        if (CollectionUtil.isNotEmpty(publishTypeList)) {
            for (Dictionary dictionary : publishTypeList) {
                if (dictionary.getValue().equals(String.valueOf(boxMhgoodsVO.getPublishType()))) {
                    boxMhgoodsVO.setPublishTypeName(dictionary.getValueName());
                    break;
                }
            }
        }
    }

    /**
     * 将商品从盲盒中移除
     * @param mhId 盲盒
     * @param id 商品
     * @return 是否成功
     */
    @Override
    public Boolean removeGoodsMh(String mhId, String id) {
        BoxMhgoods boxMhgoods = super.getById(mhId);
        if (boxMhgoods == null) {
            log.error("获取到盲盒商品 == {}",  id);
            return false;
        }
        if (boxMhgoods.getBigGoodsId().equals(id)) {
            boxMhgoods.setBigGoodsId("");
        }
        //将商品id从盲盒购买方案中剔除
        this.replaceOptionGoods(mhId, id);
        //将大奖商品从盲盒中剔除
        super.updateById(boxMhgoods);
        return true;
    }

    /**
     * 将商品从盲盒购买方案中剔除
     *
     * @param mhId 盲盒
     * @param id   商品id
     */
    private void replaceOptionGoods(String mhId, String id) {
        //查询包含这个id的数据
        LambdaQueryWrapper<BoxOption> boxOptionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        boxOptionLambdaQueryWrapper.eq(BoxOption::getMhGoodsId, mhId);
        boxOptionLambdaQueryWrapper.and(q -> q.like(BoxOption::getBiZhongGoodsId, "," + id + ",")
                .or().eq(BoxOption::getBiZhongGoodsId, id)
                .or().likeRight(BoxOption::getBiZhongGoodsId, id + ",")
                .or().likeLeft(BoxOption::getBiZhongGoodsId, "," + id));
        List<BoxOption> optionList = boxOptionService.list(boxOptionLambdaQueryWrapper);
        if (CollectionUtil.isEmpty(optionList)) {
            return;
        }
        //将这段id，从数据中剔除
        for (BoxOption boxOption : optionList) {
            String str = Arrays.stream(boxOption.getBiZhongGoodsId().split(",")).filter(num -> !num.equals(id)).collect(Collectors.joining(","));
            boxOption.setBiZhongGoodsId(StringUtils.isNotEmpty(str) ? str : StringUtils.EMPTY);
            boolean b = boxOptionService.updateById(boxOption);
            log.info("b === {}", b);
        }
    }

}




